<?php
namespace app\modules\common;
use \DateTime;

/**
 * Class TimeCalendar  通用的区间时间日历类
 * @package app\common\library
 * @version 1.0
 * @author ygzhang<ygzhang.cn@msn.com>
 */
class TimeCalendar
{
    protected $DateTime;

    public function __construct()
    {
    }

    /**
     * 是否为闰年
     * @param int $year 默认本年
     * @return bool
     */
    public function isLeapYear($year = 0)
    {
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
    }

    /**
     * [  日 ]  取得某年某月某日的开始截止的时间 [ 时间戳 ] 或[ 格式化时间 ]
     * @param int $day 默认今日
     * @param int $month 默认本月
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 His 这类的PHP date格式化字符
     * @return array  [ start=>time ,end=>time]
     */
    public function getDayTimesInterval($day = 0, $month = 0, $year = 0, $format = false)
    {
        $day = intval($day);
        $month = intval($month);
        $year = intval($year);
        if ($month < 1 || $month > 12) {
            $month = date('m');
        }
        if ($year < 1970) {
            $year = date('Y');
        }
        if ($day>=0) {
            $day = date('d');
        }else if ($day < 0) {
            $day = date('d')+$day;
            while($day<1){
                $month--;
                if ($month <=0) {
                    //自动跳转到下一年的1月
                    $month = 1;
                    $year--;
                }
                $end_days = $this->getMonthDays($month, $year);
                $day=$day+$end_days;
            }
        }

        if ($day > 27) {
            $end_days = $this->getMonthDays($month, $year);
            if ($day > $end_days) {
                //自动跳转到下一月的1日
                $day = 1;
                $month++;
                if ($month > 12) {
                    //自动跳转到下一年的1月
                    $month = 1;
                    $year++;
                }
            }
        }
        $timestamp['start'] = mktime(0, 0, 0, $month, $day, $year);
        $timestamp['end'] = mktime(23, 59, 59, $month, $day, $year);
        return $this->_formatIntervalTimes($timestamp, $format);
    }

    /**
     *[  周 ]  ISO-8601 格式年份中的某一年共有多少周
     * @param $year
     * @return int
     */
    public function getWeeks($year)
    {
        $date = new DateTime;
        $date->setISODate($year, 53);
        return ($date->format("W") === "53" ? 53 : 52);
    }

    /**
     * [  周 ]  取得某年某周的开始截止的时间 [ 时间戳 ] 或[ 格式化时间 ]
     * ISO-8601 格式年份中的第几周，每周从星期一开始
     * @param int $week 默认本周
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 YmdHis这类的PHP date格式化字符
     * @return array  [ start=>time ,end=>time]
     */
    public function getWeekTimesInterval($week = 0, $year = 0, $format = false)
    {
        $week = intval($week);
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        if ($week >= 0) {
            $week = date('W');
        } else if ($week < 0) {
            $week = date('W') + $week;
        }
        while($week<1){
            $year--;
            $week_max = $this->getWeeks($year);
            $week=$week+$week_max;
        }

        if ($week < 10) {
            $week = '0' . $week;
        }
        $timestamp['start'] = strtotime($year . 'W' . $week);
        $timestamp['end'] = strtotime('+1 week -1 second', $timestamp['start']);
        return $this->_formatIntervalTimes($timestamp, $format);
    }

    /**
     *  [  周 ] 取得某年某月有几周及每周的起始时间
     * @param int $month 默认本月
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 YmdHis这类的PHP date格式化字符
     * @return array
     */
    public function getMonthWeekList($month = 0, $year = 0, $format = false){
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        $month = intval($month);
        if ($month === 0) {
            $month = date('m');
        } else if ($month < 0) {
            $month = date('m') + $month;
            if ($month == 0) {
                $month = 12;
                $year--;
            } else if ($month < 0) {
                $month = 12 + $month + 1;
                $year--;
            }
        }
        if ($month > 12) {
            $month = $month - 12;
            $year++;
        }
        $month = intval($month);
        if ($month < 10) {
            $month = '0' . $month;
        }


        $week_list=[];
        $end_date = date('d',strtotime($year.'-'.$month.' +1 month -1 day'));
        for ($i=1; $i <$end_date ; $i=$i+7) {
            $w = date('N',strtotime($year.'-'.$month.'-'.$i));

            $week_list[] = array(
                'start'=>strtotime(date('Y-m-d 00:00:00',strtotime($year.'-'.$month.'-'.$i.' -'.($w-1).' days'))),
                'end'=>strtotime(date('Y-m-d 23:59:59',strtotime($year.'-'.$month.'-'.$i.' +'.(7-$w).' days')))
            );
        }
        foreach ($week_list as &$v){
            $v=$this->_formatIntervalTimes($v, $format);
        }
        return $week_list;
    }

    /**
     * [  月份 ]  取得某年某月的总的天数
     * @param int $month 默认本月
     * @param int $year 默认本年
     * @return int
     */
    public function getMonthDays($month = 0, $year = 0)
    {
        $month = intval($month);
        if ($month < 1 || $month > 12) {
            $month = date('m');
        }
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        return date('t', mktime(0, 0, 0, $month, 1, $year));
    }

    /**
     * [  月份 ] 取得某年某月的开始截止的时间 [ 时间戳 ] 或[ 格式化时间 ]
     * @param int $month 默认本月
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 YmdHis这类的PHP date格式化字符
     * @return array  [ start=>time ,end=>time]
     */
    public function getMonthTimesInterval($month = 0, $year = 0, $format = false)
    {
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        $month = intval($month);
        if ($month === 0) {
            $month = date('m');
        } else if ($month < 0) {
            $month = date('m') + $month;
            if ($month == 0) {
                $month = 12;
                $year--;
            } else if ($month < 0) {
                $month = 12 + $month + 1;
                $year--;
            }
        }
        if ($month > 12) {
            $month = $month - 12;
            $year++;
        }
        $month = intval($month);
        if ($month < 10) {
            $month = '0' . $month;
        }
        $end_days = $this->getMonthDays(ltrim($month, '0'), $year);
        $timestamp['start'] = mktime(0, 0, 0, $month, 1, $year);
        $timestamp['end'] = mktime(23, 59, 59, $month, $end_days, $year);
        return $this->_formatIntervalTimes($timestamp, $format);
    }

    /**
     * [  年份 ]  取得某年的总的天数
     * @param int $year 默认本年
     * @return int
     */
    public function getYearDays($year = 0)
    {

        $year = intval($year);
        if ($year == 0) {
            $year = date('Y');
        }else  if ($year < 0) {
            $year = date('Y')+$year;
        }
        if ($year < 1970) {
            $year = date('Y');
        }
        if ($this->isLeapYear($year)) {
            $days = '366';//闰年
        } else {
            $days = '365';//平年
        }
        return $days;
    }

    /**
     * [  年份 ] 取得某年的开始截止的时间 [ 时间戳 ] 或[ 格式化时间 ]
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 YmdHis这类的PHP date格式化字符
     * @return array  [ start=>time ,end=>time]
     */
    public function getYearTimesInterval($year = 0, $format = false)
    {

        $year = intval($year);
        if ($year == 0) {
            $year = date('Y');
        }else  if ($year < 0) {
            $year = date('Y')+$year;
        }
        if ($year < 1970) {
            $year = date('Y');
        }

        $timestamp['start'] = mktime(0, 0, 0, 1, 1, $year);
        $timestamp['end'] = mktime(23, 59, 59, 12, 31, $year);
        return $this->_formatIntervalTimes($timestamp, $format);
    }

    /**
     * [ 季度 ] 取得某年某一个季度的总天数
     * @param int $quarter 默认本季度
     * @param int $year 默认本年
     * @return int
     */
    public function getQuarterDays($quarter = 0, $year = 0)
    {
        $quarter = intval($quarter);
        if ($quarter < 1 || $quarter > 4) {
            $m = date('m');
            if ($m <= 3) {
                $quarter = 1;
            } else if ($m <= 6) {
                $quarter = 2;
            } else if ($m <= 9) {
                $quarter = 3;
            } else {
                $quarter = 4;
            }
        }
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        if ($quarter == 1) {
            return date('t', mktime(0, 0, 0, 1, 1, $year)) + date('t', mktime(0, 0, 0, 2, 1, $year)) + date('t', mktime(0, 0, 0, 3, 1, $year));
        } else if ($quarter == 2) {
            return date('t', mktime(0, 0, 0, 4, 1, $year)) + date('t', mktime(0, 0, 0, 5, 1, $year)) + date('t', mktime(0, 0, 0, 6, 1, $year));
        } else if ($quarter == 3) {
            return date('t', mktime(0, 0, 0, 7, 1, $year)) + date('t', mktime(0, 0, 0, 8, 1, $year)) + date('t', mktime(0, 0, 0, 9, 1, $year));
        } else {
            return date('t', mktime(0, 0, 0, 10, 1, $year)) + date('t', mktime(0, 0, 0, 11, 1, $year)) + date('t', mktime(0, 0, 0, 12, 1, $year));
        }
    }

    /**
     * [  季度 ] 取得某年某一个季度 开始截止的时间 [ 时间戳 ] 或[ 格式化时间 ]
     * @param int $quarter 默认本季度
     * @param int $year 默认本年
     * @param bool|string $format 是否需要格式化为
     * 是否需要格式化字符，如不指定（及false）默认返回 [ 时间戳 ]
     * 可以指定为date格式化字符串 YmdHis这类的PHP date格式化字符
     * @return array  [ start=>time ,end=>time]
     */
    public function getQuarterTimesInterval($quarter = 0, $year = 0, $format = false)
    {
        $quarter = intval($quarter);
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        $m = date('m');
        if ($m <= 3) {
            $step_quarter = 1;
        } else if ($m <= 6) {
            $step_quarter = 2;
        } else if ($m <= 9) {
            $step_quarter = 3;
        } else {
            $step_quarter = 4;
        }
        if($quarter>=0){
            $quarter=$step_quarter;
        }else{
            $i=$quarter;
            $j=$step_quarter;
            while ($i < 0) {
                $i++;
                $j--;
                if($j<1){
                    $j=4;
                    $year--;
                }
            }
            $quarter=$j;
        }
        if ($quarter == 1) {
            $start_month = 1;
            $end_month = 3;
        } else if ($quarter == 2) {
            $start_month = 4;
            $end_month = 6;
        } else if ($quarter == 3) {
            $start_month = 7;
            $end_month = 9;
        } else {
            $start_month = 10;
            $end_month = 12;
        }
        $end_days = $this->getMonthDays($end_month, $year);
        $timestamp['start'] = mktime(0, 0, 0, $start_month, 1, $year);
        $timestamp['end'] = mktime(23, 23, 59, $end_month, $end_days, $year);
        return $this->_formatIntervalTimes($timestamp, $format);
    }

    protected function _formatIntervalTimes($timestamp, $format=false)
    {

        if ($format === false || $format == 'timestamp' || !isset($timestamp['start']) || !isset($timestamp['end'])) {
            return $timestamp;
        }
        if (is_string($format) && !empty(trim($format))) {
            $timestamp['start']= date($format, $timestamp['start']);
            $timestamp['end']= date($format, $timestamp['end']);
        } else {
            $timestamp['start']= date('Y-m-d H:i:s', $timestamp['start']);
            $timestamp['end']= date('Y-m-d H:i:s', $timestamp['end']);
        }
        return $timestamp;
    }

    /**
     * 年份数字转中文年份
     * @param int $year 年份数字
     * @param boolean $flag 是否显示公元
     * @return string
     */
    public function timeToZhYear($year = 0, $flag = false)
    {
        $year = intval($year);
        if ($year < 1970) {
            $year = date('Y');
        }
        $array = array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九');
        $str = $flag ? '公元' : '';
        for ($i = 0; $i < 4; $i++) {
            $str .= $array[substr($year, $i, 1)];
        }
        return $str;
    }

    /**
     * 日期数字转中文
     * 用于日、月、周
     * @param int $number 日期数字
     * @return string
     */
    public function numberToCh($number)
    {
        $number = intval($number);
        $array = array('一', '二', '三', '四', '五', '六', '七', '八', '九', '十');
        $str = '';
        if ($number < 1) {
            return $str;
        }
        if ($number < 10) {
            $str .= $array[$number - 1];
        } elseif ($number < 20) {
            $str .= "十" . $array[$number - 11];
        } elseif ($number < 30) {
            $str .= "二十" . $array[$number - 21];
        } else {
            $str .= "三十" . $array[$number - 31];
        }
        return $str;
    }

    /**
     *  判断日期 所属 干支 生肖 星座
     * @param string $type 获取信息类型   XZ 星座 GZ 干支 SX 生肖
     * @param string $ymd 年月日 默认今日
     * @return string
     */
    public function magicInfo($type, $ymd = '')
    {
        $result = '';
        $ymd = trim($ymd);
        if (empty($ymd)) {
            list($y, $m, $d) = explode('-', date('Y-m-d'));
        } else {
            list($y, $m, $d) = explode('-', $ymd);
        }
        if (!isset($y) || $y < 1971) {
            return '';
        }
        if (!isset($m) || $m < 1) {
            return '';
        }
        if (!isset($d) || $d < 1) {
            return '';
        }
        switch ($type) {
            case 'XZ'://星座
                $XZDict = array('摩羯', '宝瓶', '双鱼', '白羊', '金牛', '双子', '巨蟹', '狮子', '处女', '天秤', '天蝎', '射手');
                $Zone = array(1222, 122, 222, 321, 421, 522, 622, 722, 822, 922, 1022, 1122, 1222);
                if ((100 * $m + $d) >= $Zone[0] || (100 * $m + $d) < $Zone[1])
                    $i = 0;
                else
                    for ($i = 1; $i < 12; $i++) {
                        if ((100 * $m + $d) >= $Zone[$i] && (100 * $m + $d) < $Zone[$i + 1])
                            break;
                    }
                $result = $XZDict[$i] . '座';
                break;

            case 'GZ'://干支
                $GZDict = array(
                    array('甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'),
                    array('子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥')
                );
                $i = $y - 1900 + 36;
                $result = $GZDict[0][$i % 10] . $GZDict[1][$i % 12];
                break;

            case 'SX'://生肖
                $SXDict = array('鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪');
                $result = $SXDict[($y - 4) % 12];
                break;

        }
        return $result;
    }
}